<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>📊</text></svg>">
    <title>高性能日志查看器</title>
    <style>
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }

        body, html {
            height: 100%;
            font-family: Arial, sans-serif;
            background-color: #f5f5f5;
            color: #333;
            overflow: hidden;
        }

        .container {
            height: 100vh;
            display: flex;
            flex-direction: column;
            padding: 10px;
        }

        .header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 10px;
            background-color: white;
            border-radius: 5px;
            box-shadow: 0 2px 5px rgba(0,0,0,0.1);
            margin-bottom: 10px;
        }

        .file-input {
            display: none;
        }

        .btn {
            background-color: #4285f4;
            color: white;
            border: none;
            padding: 8px 16px;
            border-radius: 4px;
            cursor: pointer;
            font-size: 14px;
            /*margin-right: 10px;*/
        }

        .btn:hover {
            background-color: #3367d6;
        }

        .btn-download {
            background-color: #34a853;
            padding: 4px 8px;
            font-size: 12px;
        }

        .btn-download:hover {
            background-color: #2d8e49;
        }

        .main-content {
            display: flex;
            flex: 1;
            gap: 10px;
            overflow: hidden;
        }

        .threads-panel {
            width: 300px;
            background-color: white;
            border-radius: 5px;
            box-shadow: 0 2px 5px rgba(0,0,0,0.1);
            display: flex;
            flex-direction: column;
            overflow: hidden;
        }

        .threads-header {
            padding: 10px;
            border-bottom: 1px solid #eee;
            display: flex;
            gap: 10px;
        }

        .threads-search {
            flex: 1;
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 4px;
        }

        .threads-list {
            flex: 1;
            overflow-y: auto;
            padding: 5px;
        }

        .logs-panel {
            flex: 1;
            display: flex;
            flex-direction: column;
            background-color: white;
            border-radius: 5px;
            box-shadow: 0 2px 5px rgba(0,0,0,0.1);
            overflow: hidden;
        }

        .logs-header {
            padding: 10px;
            border-bottom: 1px solid #eee;
            display: flex;
            gap: 10px;
        }

        .logs-search {
            flex: 1;
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 4px;
        }

        .log-container {
            flex: 1;
            overflow: hidden;
            display: flex;
            flex-direction: column;
        }

        .log-viewport {
            flex: 1;
            overflow: auto;
            position: relative;
            border-top: 2px solid red;
        }

        .log-content {
            position: absolute;
            min-width: 100%;
            white-space: nowrap; /* 确保内容不换行 */
            overflow-x: visible; /* 允许水平溢出 */
        }

        .log-line {
            padding: 4px 10px;
            font-size: 13px;
            line-height: 1.5;
            border-bottom: 1px solid #eee;
            font-family: 'Courier New', monospace;
            display: inline-block; /* 改为行内块元素 */
            width: 100%; /* 占据全部宽度 */
            border-bottom: 1px solid #eee;
            transition: background-color 0.2s;

            position: absolute;
            left: 0;
            /* 移除 right: 0 以允许水平溢出 */
            min-width: 100%; /* 确保最小宽度与容器相同 */
            will-change: transform;
            contain: content;
            backface-visibility: hidden;
            white-space: nowrap; /* 确保内容不换行 */
            overflow: visible; /* 允许内容溢出 */
        }

        .log-line:hover {
            background-color: #f0f7ff;
        }

        .stats {
            display: flex;
            gap: 15px;
            font-size: 14px;
            padding: 12px 15px;
            background-color: #f8f9fa;
            border-radius: 6px;
            box-shadow: 0 1px 3px rgba(0,0,0,0.1);
            margin-bottom: 15px;
            flex-wrap: wrap;
            align-items: center;
            border: 1px solid #e1e4e8;
        }

        .stats div {
            display: flex;
            align-items: center;
            padding: 6px 10px;
            border-radius: 4px;
            background-color: white;
            box-shadow: 0 1px 2px rgba(0,0,0,0.05);
            cursor: pointer;  /* 添加可点击光标 */
            transition: all 0.2s;  /* 添加过渡效果 */
        }

        .stats div:hover {
            background-color: #e8f0fe !important;  /* 悬停效果 */
        }

        .stats div.active {
            box-shadow: inset 0 0 0 2px #4285f4;  /* 选中状态 */
        }


        .stats span {
            font-weight: 600;
            margin-left: 5px;
        }

        /* 为不同级别添加颜色标识 */
        .stats .debug-count {
            color: #1976d2;
            border-left: 3px solid #1976d2;
        }

        .stats .info-count {
            color: #388e3c;
            border-left: 3px solid #388e3c;
        }

        .stats .warn-count {
            color: #ffa000;
            border-left: 3px solid #ffa000;
        }

        .stats .error-count {
            color: #d32f2f;
            border-left: 3px solid #d32f2f;
        }

        .stats .total-count {
            color: #6c757d;
            border-left: 3px solid #6c757d;
            font-weight: bold;
        }
        .highlight {
            background-color: #ffeb3b;
            padding: 0 2px;
            border-radius: 2px;
        }

        .level-DEBUG { color: #1976d2; }
        .level-INFO { color: #388e3c; }
        .level-WARN { color: #ffa000; }
        .level-ERROR { color: #d32f2f; }
        .level-FATAL { color: #b71c1c; }
        .level-TRACE { color: #7b1fa2; }

        .thread-item {
            padding: 8px 10px;
            margin-bottom: 5px;
            border-radius: 4px;
            cursor: pointer;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .thread-item:hover {
            background-color: #e8f0fe;
        }

        .thread-item.active {
            background-color: #4285f4;
            color: white;
        }

        .thread-info {
            flex: 1;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .thread-count {
            font-size: 12px;
            color: #666;
            margin-left: 10px;
        }

        .thread-item.active .thread-count {
            color: #e0e0e0;
        }

        .thread-actions {
            display: flex;
            gap: 5px;
        }

        .progress-container {
            position: fixed;
            bottom: 20px;
            left: 50%;
            transform: translateX(-50%);
            background-color: white;
            padding: 15px 25px;
            border-radius: 4px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
            display: none;
            border: 1px solid #ddd;
            z-index: 100;
        }

        .log-content {
            position: absolute;
            min-width: 100%;
            width: auto; /* 改为自动宽度 */
            white-space: nowrap;
            overflow-x: visible; /* 允许水平滚动 */
        }

        .log-viewport {
            overflow: auto; /* 确保滚动容器允许双向滚动 */
        }


        /* 输入选项样式 */
        .input-options {
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .or-divider {
            color: #666;
            padding: 0 5px;
        }

        /* 模态框样式 */
        .modal {
            display: none;
            position: fixed;
            z-index: 1000;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0,0,0,0.7);
        }

        .modal-content {
            background-color: #fff;
            margin: 5% auto;
            padding: 20px;
            border-radius: 5px;
            width: 80%;
            max-width: 800px;
            max-height: 80vh;
            display: flex;
            flex-direction: column;
        }

        .modal-content h2 {
            margin-bottom: 15px;
            color: #4285f4;
        }

        #pasteArea {
            flex: 1;
            min-height: 300px;
            padding: 10px;
            font-family: 'Courier New', monospace;
            font-size: 14px;
            border: 1px solid #ddd;
            border-radius: 4px;
            resize: none;
            margin-bottom: 15px;
        }

        .close {
            color: #aaa;
            float: right;
            font-size: 28px;
            font-weight: bold;
            cursor: pointer;
        }

        .close:hover {
            color: #333;
        }




        /* 连接控制区域样式 */
        #serverUrl {
            flex: 1;
            max-width: 500px;
            width: 300px;
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 4px;
        }

        #connectBtn {
            margin-left: 10px;
            min-width: 120px;
        }

        .connected {
            background-color: #34a853;
        }

        .disconnected {
            background-color: #ea4335;
        }


        /* 添加可点击状态样式 */
        .clickable-stat {
            cursor: pointer;
            transition: all 0.2s;
        }

        .clickable-stat:hover {
            background-color: #e8f0fe !important;
        }

        .clickable-stat.active {
            box-shadow: inset 0 0 0 2px #4285f4;
        }


        /*上下文行数:*/
        .context-control {
            display: flex;
            align-items: center;
            margin-left: 10px;
            font-size: 14px;
        }

        #contextLines {
            width: 50px;
            margin-left: 5px;
            padding: 4px;
            border: 1px solid #ddd;
            border-radius: 4px;
        }


        .resizable-container {
            display: flex;
            flex: 1;
            position: relative;
            min-width: 0; /* 重要：防止内容溢出 */
        }

        .threads-panel {
            width: 300px; /* 默认宽度 */
            min-width: 200px; /* 最小宽度 */
            max-width: 80%; /* 最大宽度 */
            resize: none; /* 禁用默认resize */
            overflow: auto;
        }

        .resize-handle {
            width: 8px;
            background: #ddd;
            cursor: col-resize;
            transition: background 0.2s;
        }

        .resize-handle:hover {
            background: #4285f4;
        }

        .logs-panel {
            flex: 1;
            min-width: 300px; /* 最小宽度 */
            overflow: hidden;
        }
        /* 拖动时的样式 */
        .resizing {
            user-select: none;
            -webkit-user-select: none;
        }

        .resizing .log-line {
            pointer-events: none;
        }


        /* 下载配置模态框  在原有CSS中添加 */
        .separator-line {
            background-color: #f0f0f0;
            font-weight: bold;
            color: #666;
            border-top: 2px dashed #ccc;
            border-bottom: 2px dashed #ccc;
            text-align: left !important; /* 确保默认左对齐 */
            padding-left: 10px !important; /* 覆盖内联样式 */
        }
        .download-progress {
            position: absolute;
            bottom: 10px;
            left: 10px;
            right: 10px;
            background: rgba(255, 255, 255, 0.9);
            padding: 8px 12px;
            border-radius: 4px;
            box-shadow: 0 2px 5px rgba(0,0,0,0.2);
            font-size: 14px;
            text-align: center;
            z-index: 100;
            display: none;
        }
        .download-select {
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 4px;
            margin-right: 10px;
        }

        .config-list {
            max-height: 300px;
            overflow-y: auto;
            margin-bottom: 20px;
            border: 1px solid #eee;
            border-radius: 4px;
            padding: 10px;
        }

        .config-item {
            padding: 10px;
            border-bottom: 1px solid #eee;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .config-info {
            flex: 1;
            overflow: hidden;
            text-overflow: ellipsis;
        }

        .config-actions {
            display: flex;
            gap: 5px;
        }

        .config-input {
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 4px;
            margin-bottom: 10px;
            width: 100%;
        }

        .config-form {
            margin-top: 20px;
        }

        .download-progress {
            position: absolute;
            bottom: 10px;
            left: 10px;
            right: 10px;
            background: rgba(255,255,255,0.9);
            padding: 5px;
            border-radius: 4px;
            display: none;
        }


        /* 全屏按钮样式 */
        .btn-fullscreen {
            background: none;
            border: none;
            cursor: pointer;
            padding: 5px;
            color: #666;
        }

        .btn-fullscreen:hover {
            color: #333;
        }

        /* 全屏状态下的样式 */
        .logs-panel.fullscreen {
            position: fixed;
            top: 0;
            left: 0;
            width: 100vw;
            height: 100vh;
            z-index: 1000;
            background: white;
            overflow: auto;
        }

        /* 全屏时隐藏其他元素（可选） */
        body.logs-fullscreen #threadsPanel,
        body.logs-fullscreen .other-panels {
            display: none;
        }

        /* 搜索无结果提示 */
        .search-alert {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0,0,0,0.5);
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 1000;
        }

        .search-alert .alert-content {
            background: white;
            padding: 20px;
            border-radius: 5px;
            text-align: center;
            max-width: 400px;
        }

        .search-alert p {
            margin-bottom: 20px;
            font-size: 16px;
        }

        /* 复制按钮样式 */
        .btn-copy {
            display: flex;
            align-items: center;
            gap: 5px;
            margin-left: 10px;
        }

        .copy-tooltip {
            position: absolute;
            top: -30px;
            left: 50%;
            transform: translateX(-50%);
            background: #333;
            color: white;
            padding: 4px 8px;
            border-radius: 4px;
            font-size: 12px;
            white-space: nowrap;
        }

        /* 暂存功能样式 */
        .btn-storage {
            display: flex;
            align-items: center;
            gap: 5px;
            margin-left: 10px;
        }

        .storage-tooltip {
            position: absolute;
            top: -30px;
            left: 50%;
            transform: translateX(-50%);
            background: #333;
            color: white;
            padding: 4px 8px;
            border-radius: 4px;
            font-size: 12px;
            white-space: nowrap;
        }

        .storage-panel {
            position: fixed;
            right: 20px;
            bottom: 20px;
            width: 350px;
            max-height: 500px;
            background: white;
            border-radius: 5px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.2);
            display: flex;
            flex-direction: column;
            z-index: 100;
            overflow: hidden;
        }

        .storage-header {
            padding: 10px;
            border-bottom: 1px solid #eee;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .storage-list {
            flex: 1;
            overflow-y: auto;
            padding: 10px;
        }

        .storage-item {
            display: flex;
            align-items: center;
            padding: 10px;
            border-bottom: 1px solid #eee;
            cursor: pointer;
        }

        .storage-item input[type="radio"] {
            display: inline-block; /* 确保显示 */
            margin-right: 10px; /* 添加间距 */
        }


        .storage-info {
            flex: 1;
        }

        .storage-desc {
            font-weight: bold;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }

        .storage-footer {
            padding: 10px;
            display: flex;
            justify-content: space-between;
            border-top: 1px solid #eee;
        }
        
        .storage-meta {
            display: flex;
            gap: 10px;
            font-size: 12px;
            color: #666;
        }

        .storage-actions {
            display: flex;
            gap: 5px;
        }

        .storage-empty {
            padding: 20px;
            text-align: center;
            color: #666;
        }


        /* 折叠框样式 */
        .foldable-container {
            flex-shrink: 0;
            max-height: 40%;
            overflow-y: auto;
        }

        .foldable-box {
            border: 1px solid #ddd;
            border-radius: 4px;
            margin-bottom: 10px;
            overflow: hidden;
        }

        .foldable-header {
            background-color: #f5f5f5;
            padding: 8px 12px;
            cursor: pointer;
            display: flex;
            justify-content: space-between;
            align-items: center;
            border-bottom: 1px solid #ddd;
        }

        .foldable-header:hover {
            background-color: #e8f0fe;
        }

        .foldable-title {
            font-weight: bold;
            color: #4285f4;
        }

        .foldable-content {
            background-color: #eef3fa;
            max-height: 200px;
            overflow-y: auto;
        }

        .foldable-log-line {
            padding: 4px 10px;
            font-size: 13px;
            line-height: 1.5;
            border-bottom: 1px solid #eee;
            font-family: 'Courier New', monospace;
            white-space: nowrap;
        }

        .foldable-log-line:hover {
            background-color: #f0f7ff;
        }

        .foldable-actions {
            display: flex;
            gap: 5px;
        }

        .foldable-btn {
            background: none;
            border: none;
            cursor: pointer;
            padding: 2px 5px;
            color: #666;
        }

        .foldable-btn:hover {
            color: #333;
        }

        .folded .foldable-content {
            display: none;
        }

        .fold-icon {
            transition: transform 0.2s;
        }

        .folded .fold-icon {
            transform: rotate(-90deg);
        }
        
    </style>
</head>
<body>
<div class="container">
    <div class="header">
        <h1 style="color: #4285f4;">日志查看器</h1>
        <div class="input-options">
            <input type="file" id="fileInput" class="file-input" accept=".log,.txt">
            <button id="loadBtn" class="btn">加载日志文件</button>
            <div class="or-divider">或</div>
            <button id="pasteBtn" class="btn">粘贴日志</button>
            <div class="or-divider">或</div>
            <button id="connectBtn" class="btn">连接日志服务</button>
            <input type="text" id="serverUrl" placeholder="ws://localhost:8080/logs" value="ws://localhost:8080/logs">
            <div class="or-divider">或</div>
            <select id="downloadSelect" class="download-select">
                <option value="">选择下载配置</option>
                <!-- 选项将通过JS动态添加 -->
            </select>
            <button id="downloadBtn" class="btn">下载日志</button>
            <button id="manageDownloadBtn" class="btn">管理配置</button>
            <button id="toggleStorageBtn" class="btn">显示暂存日志</button>

        </div>

    </div>
    
    <div class="stats" id="stats">
        <div class="total-count clickable-stat" data-level="all">
            总行数: <span id="totalLines">0</span>
        </div>
        <div class="debug-count clickable-stat" data-level="DEBUG">
            DEBUG: <span id="debugCount">0</span>
        </div>
        <div class="info-count clickable-stat" data-level="INFO">
            INFO: <span id="infoCount">0</span>
        </div>
        <div class="warn-count clickable-stat" data-level="WARN">
            WARN: <span id="warnCount">0</span>
        </div>
        <div class="error-count clickable-stat" data-level="ERROR">
            ERROR: <span id="errorCount">0</span>
        </div>
    </div>
    
    <div class="main-content">
        <div class="resizable-container">
            <div class="threads-panel" id="threadsPanel">
                <div class="threads-header">
                    <input type="text" id="threadSearch" class="threads-search" placeholder="搜索线程...">
                </div>
                <div class="threads-list" id="threadsList"></div>
            </div>

            <div class="resize-handle"></div>

            <div class="logs-panel">
                <div class="logs-header">
                    <input type="text" id="logSearch" class="logs-search" placeholder="搜索日志内容...">
                    <button id="searchBtn" class="btn">搜索</button>
                    <button id="copyBtn" class="btn btn-copy">复制</button>
                    <button id="storageBtn" class="btn btn-storage">暂存</button>
                    <button id="fullscreenBtn" class="btn-fullscreen" title="全屏">
                        <svg viewBox="0 0 24 24" width="20" height="20">
                            <path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"/>
                        </svg>
                    </button>
                    <div class="context-control">
                        <span>上下文行数:</span>
                        <input type="number" id="contextLines" min="0" max="20" value="5">
                    </div>
                </div>
                <div class="log-container">
                    <!--折叠框-->
                    <div class="foldable-container" id="foldableContainer"></div>
                    <div class="log-viewport" id="logViewport">
                        <div class="log-content" id="logContent"></div>
                    </div>
                </div>
            </div>
        </div>
        
    </div>

    <div class="progress-container" id="progressContainer">
        <div>正在处理文件: <span id="progressPercent">0</span>%</div>
        <div>已加载行数: <span id="loadedLines">0</span></div>
    </div>


    <!-- 添加粘贴模态框 (放在container末尾) -->
    <div id="pasteModal" class="modal">
        <div class="modal-content">
            <span class="close">&times;</span>
            <h2>粘贴日志内容</h2>
            <textarea id="pasteArea" placeholder="请在此粘贴您的日志内容..."></textarea>
            <button id="submitPaste" class="btn">提交</button>
        </div>
    </div>

    <!-- 下载配置模态框 -->
    <div id="downloadConfigModal" class="modal">
        <div class="modal-content">
            <span class="close download-close">&times;</span>
            <h2>管理日志下载配置</h2>
            <div id="downloadConfigList" class="config-list">
                <!-- 配置项将通过JS动态添加 -->
            </div>
            <div class="config-form">
                <input type="text" id="configAlias" placeholder="配置别名" class="config-input">
                <input type="text" id="configUrl" placeholder="日志下载URL" class="config-input">
                <button id="saveConfigBtn" class="btn">保存配置</button>
            </div>
        </div>
    </div>

    <div id="storagePanel" class="storage-panel" style="display:none;">
        <div class="storage-header">
            <h3>暂存日志</h3>
            <button class="btn btn-clear-storage">清空</button>
        </div>
        <div class="storage-list"></div>
        <div class="storage-footer">
            <button id="loadSelectedStorage" class="btn">加载选中</button>
            <button id="closeStoragePanel" class="btn">关闭</button>
        </div>
    </div>
    
</div>

<script src="app.js"></script>
</body>
</html>
